/**
 * \file PageTable.h
 * \brief x86 page tables
 * \author Corey Tabaka
 */

/*
   Copyright 2006 Corey Tabaka

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include <ktypes.h>
#include <Sync.h>
#include <Queue.h>

#ifndef __KERNEL_PAGE_TABLE_H__
#define __KERNEL_PAGE_TABLE_H__

/*
 * Page Directory/Table Entry
 */

typedef union {
	struct {
		uint32 present : 1;
		uint32 rw : 1;
		uint32 user_priv : 1;
		uint32 write_through : 1;
		uint32 cache_disable : 1;
		uint32 accessed : 1;
		uint32 dirty : 1;
		uint32 size : 1;
		uint32 global : 1;
		uint32 available : 3;
		uint32 base : 20;
	};
	
	void *page;
} page_entry_t;

typedef page_entry_t page_table_t[1024];

#define PAGE_SIZE	4096
#define PAGE_ALIGN	4096
#define PAGE_MASK	0xfff
#define PAGE_SHIFT	12

#define PAGE_ROUND(a) (((a) + PAGE_MASK) & ~PAGE_MASK)

enum {
	PAGE_NONE			= 0x000,
	
	PAGE_PRESENT		= 0x001,
	PAGE_WRITABLE		= 0x002,
	PAGE_USER_PRIV		= 0x004,
	PAGE_WRITE_THROUGH	= 0x008,
	PAGE_CACHE_DISABLE	= 0x010,
	PAGE_ACCESSED		= 0x020,
	PAGE_DIRTY			= 0x040,
	PAGE_SIZE_4M		= 0x080,
	PAGE_GLOBAL			= 0x100,
	
	PAGE_MODE_MASK		= PAGE_WRITABLE | PAGE_USER_PRIV | PAGE_WRITE_THROUGH
		| PAGE_CACHE_DISABLE | PAGE_GLOBAL,
	
	PAGE_STATE_MASK		= PAGE_PRESENT | PAGE_ACCESSED | PAGE_DIRTY,
	
	PAGE_ACTIVE_MASK	= PAGE_ACCESSED | PAGE_DIRTY,
	
	PAGE_ATTR_MASK		= PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER_PRIV
		| PAGE_WRITE_THROUGH | PAGE_CACHE_DISABLE | PAGE_ACCESSED | PAGE_DIRTY
		| PAGE_SIZE_4M | PAGE_GLOBAL,
};

enum {
	ACQUIRE_MODE_KEEP_PDE	 	= 0x000,
	ACQUIRE_MODE_NEW_PDE	 	= 0x001,
	ACQUIRE_MODE_COPY_PDE	 	= 0x002,
	ACQUIRE_MODE_KEEP_PTE	 	= 0x000,
	ACQUIRE_MODE_REPLACE_PTE	= 0x010,
	ACQUIRE_MODE_ENABLE_CACHE	= 0x000,
	ACQUIRE_MODE_DISABLE_CACHE	= 0x100,
	ACQUIRE_MODE_READ_ONLY		= 0x200,
};

class PageTable {
	private:
	
	page_entry_t *pageDir;
	InterruptLock lock;
	
	public:
		
	static void initialize(void);
	
	PageTable(void);
	~PageTable(void);
	
	void *acquire(void *pa, void *va, uint32 len, bool user,
		uint32 mode = ACQUIRE_MODE_KEEP_PDE | ACQUIRE_MODE_KEEP_PTE);
	void *physicalFromEffective(void *va, bool *present=0);
	void copy(const PageTable *pd);
	
	void release(void *va, uint32 len);
	
	// read page table entry flags into Page flags 
	bool getFlags(uint32 va, uint32 &flags);
	
	// update page table entry with Page flags
	bool updateFlags(uint32 va, uint32 flags, uint32 mask);
	
	bool isCurrent(void);
	void makeCurrent(void);
};

#endif


























